#include "lsv_rcache_v1.h"
#include "lsv_log.h"
#include "lsv_volume.h"
#include "volume_proto.h"
#include "list.h"

/*init read cache*/
int lsv_rcache_init(lsv_volume_proto_t * volume_proto){
        lsv_s32_t err = 0;
        lsv_s32_t i = 0;
        lsv_rcache_t * rcache = NULL;

        volume_proto->rcache = (void *)malloc(sizeof(lsv_rcache_t));
        if(NULL == volume_proto->rcache){
                /*print log*/
                err = -ENOMEM;
                return err;
        }
        memset(volume_proto->rcache, 0, sizeof(lsv_rcache_t));

        rcache = (lsv_rcache_t *)volume_proto->rcache;
        rcache->head = 0;
        rcache->tail = 0;
        rcache->chunk_num = 0;
        rcache->total_chunk = LSV_RCACHE_CHUNK_NUM_MAX;
        rcache->chunk_id = (lsv_u64_t *) malloc(LSV_RCACHE_CHUNK_NUM_MAX * sizeof(lsv_u64_t));
        if(NULL == rcache->chunk_id){
                /*print log*/
                err = -ENOMEM;
                return err;
        }
        memset(rcache->chunk_id, 0, sizeof(lsv_u64_t) * LSV_RCACHE_CHUNK_NUM_MAX);
        rcache->chunk_buf = (lsv_s8_t **)malloc(sizeof(lsv_s8_t *) * LSV_RCACHE_CHUNK_NUM_MAX);
        if(NULL == rcache->chunk_buf){
                /*print log*/
                err = -ENOMEM;
                return err;
        }
        memset(rcache->chunk_buf, 0, sizeof(lsv_s8_t *) * LSV_RCACHE_CHUNK_NUM_MAX);

        for(i = 0; i < LSV_RCACHE_CHUNK_NUM_MAX; i++){
                rcache->chunk_buf[i] = (lsv_s8_t *) malloc(sizeof(lsv_s8_t) * LSV_CHUNK_SIZE);
                if(NULL == rcache->chunk_buf[i]){
                        /*print log*/
                        err = -ENOMEM;
                        return err;
                }
                memset(rcache->chunk_buf[i], 0, sizeof(lsv_s8_t) * LSV_CHUNK_SIZE);
        }
        lsv_rwlock_init(&rcache->rwlock);
        return err;
}

int lsv_rcache_release(lsv_volume_proto_t * volume_proto){
        lsv_s32_t err = 0;
        lsv_s32_t i = 0;
        lsv_rcache_t * rcache = NULL;

        rcache = (lsv_rcache_t *)volume_proto->rcache;

        for(i = 0; i < LSV_RCACHE_CHUNK_NUM_MAX; i ++){
                free(rcache->chunk_buf[i]);
                rcache->chunk_buf[i] = NULL;
        	lsv_rwlock_destroy(&rcache->rwlock);
        }
        free(rcache->chunk_buf);
        rcache->chunk_buf = NULL;
        free(volume_proto->rcache);
        volume_proto->rcache = NULL;
        return err;
}

int lsv_rcache_page_clean(lsv_volume_proto_t * volume_proto, lsv_u32_t chunk_id, lsv_s32_t chunk_off){
        lsv_s32_t err = 0;
	//lsv_rcache_page_hash_index_regc(volume_proto, chunk_id, chunk_off);	
        return err;
}


/*chunk_id == LSV_CHUNK_NULL, clean all chunks*/
int lsv_rcache_clean(lsv_volume_proto_t * volume_proto, lsv_u32_t chunk_id){
        lsv_s32_t err = 0;
        lsv_s32_t i = 0;
        lsv_rcache_t * rcache = NULL;

        rcache = (lsv_rcache_t *)volume_proto->rcache;
        for(i = 0; i < rcache->chunk_num; i++){
                if(rcache->chunk_id[i] == chunk_id || LSV_CHUNK_NULL == chunk_id){
        		lsv_wrlock(&rcache->rwlock);
                        rcache->chunk_id[i] = 0;
                        memset(rcache->chunk_buf[i], 0, sizeof(lsv_s8_t) * LSV_CHUNK_SIZE);
        		lsv_rwunlock(&rcache->rwlock);
                }

        }
        return err;
}

int lsv_rcache_lookup(lsv_volume_proto_t *volume_proto, lsv_u32_t chunk_id,
                lsv_s32_t chunk_offset,lsv_u64_t lba, lsv_s32_t size, const raw_io_t *rio, buffer_t *append_buf){
        lsv_s32_t err = 0;
        lsv_s32_t tail_idx = 0;
	lsv_s32_t page_offset = lba % LSV_PAGE_SIZE;
        lsv_rcache_t *rcache = NULL;

        if(LSV_CHUNK_NULL == chunk_id){
                DERROR("lookup rcache , chunk_id is 0, the parameter is wrong!\n");
                err = -EINVAL;
                return err;
        }

        rcache = (lsv_rcache_t *)volume_proto->rcache;
        tail_idx = rcache -> tail;

	err = lsv_rcache_page_search(volume_proto, chunk_id, chunk_offset, page_offset, size, append_buf);
	if(err == size){
		return size;
	}

        volume_proto->read_rc_miss++;

        DINFO("request page not in readcache, call lsv_log_slog_read\n");

	lsv_wrlock(&rcache->rwlock);

	err = lsv_rcache_page_search(volume_proto, chunk_id, chunk_offset, page_offset, size, append_buf);
	if(err == size){
                lsv_rwunlock(&rcache->rwlock);
		return size;
	}

	err = lsv_rcache_load_chunk(volume_proto, chunk_id, chunk_offset, page_offset, size, append_buf);
	if(err != size){
		lsv_rwunlock(&rcache->rwlock);
		return err;
	}

	lsv_rwunlock(&rcache->rwlock);
        return size;
}
